﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.Windows;
using Autodesk.AutoCAD.GraphicsSystem;
using Autodesk.AutoCAD.GraphicsInterface;
using System.Collections.Generic;
using System.Linq;
using System;


namespace UseEntityJig
{
    public class AddBundleLengthDimension
    {
        // 一个Bundle 只有一个文本标注
        // 保存将要删除的标注ID  <线,标注>
        // 依赖于某种可见特征（例如箭头或尺寸线）来定位或选择标注对象
        public List<LineDimension> lineDimensions = new List<LineDimension>();
        // 文本标注偏移量
        private double offsetDistance_x = 5.0; // 偏移在X方向的左方
        private double offsetDistance_y = 3.0; // 偏移在X方向，即右方

        /// <summary>
        /// 增加Bundle 长度 标注
        /// </summary>
        [CommandMethod("AddBundle")]
        public void AddBundle()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            PromptPointOptions promptStartOptions = new PromptPointOptions("\n请选择起始点: ");
            PromptPointResult promptStartResult = ed.GetPoint(promptStartOptions);

            if (promptStartResult.Status != PromptStatus.OK)
                return;

            Point3d startPoint = promptStartResult.Value;

            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable blockTable = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

                // 在起始点创建第一个节点
                double nodeRadius = 1.0;
                Circle startNode = new Circle(startPoint, Vector3d.ZAxis, nodeRadius);
                startNode.Color = Color.FromColorIndex(ColorMethod.ByAci, 40);
                btr.AppendEntity(startNode);
                trans.AddNewlyCreatedDBObject(startNode, true);

                // 创建直线对象 此时没有终点
                Line line = new Line(startPoint, startPoint);

                // 设置线属性
                LinetypeTable acLineTypTbl = trans.GetObject(db.LinetypeTableId, OpenMode.ForRead) as LinetypeTable;
                // 确保线型ZShape已加载
                if (!acLineTypTbl.Has("Z_LINE"))
                {
                    db.LoadLineTypeFile("Z_LINE", "CustomLinetype.lin");
                }

                // 设置线条的线型为Z_LINE
                if (acLineTypTbl.Has("Z_LINE"))
                {
                    line.Linetype = "Z_LINE";
                }
                line.Color = Color.FromColorIndex(ColorMethod.ByAci, 142);

                // 创建自定义Jig实例
                DrawBundleWithNodesJig jig = new DrawBundleWithNodesJig(line, startPoint, nodeRadius);

                // 提交事务，使得第一个小圆圈在选择起始点后立即显示
                trans.Commit();

                // 运行Jig来获取用户输入
                PromptResult promptResult = ed.Drag(jig);

                if (promptResult.Status == PromptStatus.OK)
                {
                    // 开启新的事务以继续绘制终点和标注
                    using (Transaction trans2 = db.TransactionManager.StartTransaction())
                    {
                        btr = trans2.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

                        // 将直线加入到块表记录中
                        btr.AppendEntity(line);
                        trans2.AddNewlyCreatedDBObject(line, true);
                        //jig.AppendEntities(btr, trans2);

                        // 在终点创建第二个节点
                        Circle endNode = new Circle(jig.EndPoint, Vector3d.ZAxis, nodeRadius);
                        endNode.Color = Color.FromColorIndex(ColorMethod.ByAci, 40);
                        btr.AppendEntity(endNode);
                        trans2.AddNewlyCreatedDBObject(endNode, true);

                        // 计算新线段的长度
                        double length = startPoint.DistanceTo(jig.EndPoint);

                        // 添加长度标注
                        //AddLengthAnnotation(trans, btr, line, length);
                        AddLengthDBText(trans, btr, line, length);

                        // 重新调整直线的起点和终点，使其与小圆圈相切
                        Vector3d startToEnd = jig.EndPoint - startPoint;
                        Vector3d direction = startToEnd.GetNormal();

                        // 调整直线的起点和终点，使其与圆相切
                        line.StartPoint = startPoint + direction * nodeRadius;
                        line.EndPoint = jig.EndPoint - direction * nodeRadius;

                        // 提交事务
                        trans2.Commit();
                    }
                }
            }
        }

        #region 直线分断 自动标记线段标注Dimension

        [CommandMethod("AddBundleNode")]
        public void AddBundleNode()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            Matrix3d mt = ed.CurrentUserCoordinateSystem;
            Vector3d normal = mt.CoordinateSystem3d.Zaxis;

            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable blockTable = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;

                //// 提示用户选择截断点
                //PromptPointOptions pointOptions = new PromptPointOptions("\n请选择截断点: ");
                //PromptPointResult pointResult = ed.GetPoint(pointOptions);

                //if (pointResult.Status != PromptStatus.OK)
                //    return;

                CircleJig circleJig = new CircleJig(normal);

                for (; ; )
                {
                    // 拖动
                    PromptResult resJig = ed.Drag(circleJig);
                    // 放弃, 则退出.
                    if (resJig.Status == PromptStatus.Cancel)
                    {
                        return;
                    }
                    // 确定, 则将圆添加到数据库
                    if (resJig.Status == PromptStatus.OK)
                    {
                        btr.AppendEntity(circleJig.GetEntity());
                        trans.AddNewlyCreatedDBObject(circleJig.GetEntity(), true);
                        break;
                    }
                }

                Point3d breakPoint = circleJig.m_CenterPt;
                double nodeRadius = circleJig.m_Radius; // 半径为1 的圆圈

                // 获取在截断点附近的所有直线
                PromptSelectionResult selectionResult = ed.SelectCrossingWindow(breakPoint - new Vector3d(0.1, 0.1, 0),
                                                                                breakPoint + new Vector3d(0.1, 0.1, 0));

                if (selectionResult.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("\n没有找到直线对象。");
                    return;
                }

                // 筛选出最近的直线
                ObjectId closestLineId = ObjectId.Null;
                double minDistance = double.MaxValue;

                foreach (SelectedObject selectedObj in selectionResult.Value)
                {
                    Entity entity = trans.GetObject(selectedObj.ObjectId, OpenMode.ForRead) as Entity;
                    if (entity is Line line)
                    {
                        double distance = line.GetClosestPointTo(breakPoint, false).DistanceTo(breakPoint);
                        if (distance < minDistance)
                        {
                            minDistance = distance;
                            closestLineId = selectedObj.ObjectId;
                        }
                    }
                }

                if (closestLineId == ObjectId.Null)
                {
                    ed.WriteMessage("\n没有找到符合条件的直线。");
                    return;
                }

                // 获取最近的直线
                Line originalLine = trans.GetObject(closestLineId, OpenMode.ForWrite) as Line;


                // 保存原直线的属性
                string lineType = originalLine.Linetype;
                double lineTypeScale = originalLine.LinetypeScale;
                Color color = originalLine.Color;
                string layer = originalLine.Layer;
                Autodesk.AutoCAD.DatabaseServices.LineWeight lineWeight = originalLine.LineWeight;

                // 创建node3圆圈，中心点为截断点
                Circle node3 = new Circle(breakPoint, Vector3d.ZAxis, nodeRadius);
                node3.Color = Color.FromColorIndex(ColorMethod.ByAci, 40);
                btr.AppendEntity(node3);
                trans.AddNewlyCreatedDBObject(node3, true);

                // 获取直线的起点和终点
                Point3d startPoint = originalLine.StartPoint;
                Point3d endPoint = originalLine.EndPoint;

                // 直接打开图纸文件 分割

                // 计算向量
                Vector3d lineDirection = (endPoint - startPoint).GetNormal();

                // 计算与圆圈相切的点
                Point3d firstTangentPoint = breakPoint - lineDirection * nodeRadius;
                Point3d secondTangentPoint = breakPoint + lineDirection * nodeRadius;

                // 创建两条新的直线段
                Line lineSegment1 = new Line(startPoint, firstTangentPoint);// 线段起点不变，终点减1
                Line lineSegment2 = new Line(secondTangentPoint, endPoint);// 线段终点不变，起始点减1

                // 复制原直线的属性到新直线段
                lineSegment1.Linetype = lineType;
                lineSegment1.LinetypeScale = lineTypeScale;
                lineSegment1.Color = color;
                lineSegment1.Layer = layer;
                lineSegment1.LineWeight = lineWeight;

                lineSegment2.Linetype = lineType;
                lineSegment2.LinetypeScale = lineTypeScale;
                lineSegment2.Color = color;
                lineSegment2.Layer = layer;
                lineSegment2.LineWeight = lineWeight;

                // 将新线段添加到块表记录中
                btr.AppendEntity(lineSegment1);
                trans.AddNewlyCreatedDBObject(lineSegment1, true);
                btr.AppendEntity(lineSegment2);
                trans.AddNewlyCreatedDBObject(lineSegment2, true);


                // 为新线段添加长度标注
                // 原始长度。即以Node圆心为起点 实际大2

                Vector3d startToEnd = endPoint - startPoint;
                Vector3d direction = startToEnd.GetNormal();

                // 调整直线的起点和终点，使其与圆心相连
                startPoint = startPoint - direction * nodeRadius;
                endPoint = endPoint + direction * nodeRadius;


                // 当前选中的Bundle长度
                int bundleLength = 0;

                var selectedBundle = lineDimensions.FirstOrDefault(x => x.LineObjectId == originalLine.ObjectId);
                if (selectedBundle != null)
                {
                    bundleLength = selectedBundle.LineLength;
                }
                else
                {
                    double blength = startPoint.DistanceTo(endPoint);
                    bundleLength = (int)Math.Round(blength, 0, MidpointRounding.AwayFromZero);

                    // 将待删除的标注存入字典
                    lineDimensions.Add(new LineDimension { LineObjectId = originalLine.ObjectId, DimensionObjectId = originalLine.ObjectId, LineLength = bundleLength });

                }

                double llength = startPoint.DistanceTo(breakPoint);
                double rlength = breakPoint.DistanceTo(endPoint);
                int leftLength = (int)Math.Round(llength, 0, MidpointRounding.AwayFromZero);
                int rightLength = (int)Math.Round(rlength, 0, MidpointRounding.AwayFromZero);

                // bundleLength是奇数，中分后，线段为小数，这时需要左边缩小
                if (bundleLength % 2 != 0 && leftLength == rightLength)
                {
                    leftLength -= 1;
                }

                int deltaLength = bundleLength - leftLength - rightLength;// 差异长度
                if (deltaLength > -1)
                {
                    if (leftLength > rightLength)
                    {
                        leftLength = leftLength + deltaLength;
                    }
                    else
                    {
                        rightLength = rightLength + deltaLength;
                    }
                }


                // 删除原来的长度文本标注
                //RemoveLengthAnnotation(trans, btr, originalLine);
                RemoveOldLengthText(trans, btr, originalLine);

                //AddLengthAnnotation(trans, btr, lineSegment1, leftLength);
                //AddLengthAnnotation(trans, btr, lineSegment2, rightLength);

                AddLengthDBText(trans, btr, lineSegment1, leftLength);
                AddLengthDBText(trans, btr, lineSegment2, rightLength);

                // 删除原来的直线
                originalLine.Erase();

                // 提交事务
                trans.Commit();
            }
        }
         
        private void RemoveLengthAnnotation(Transaction trans, BlockTableRecord btr, Line originalLine)
        {
            if (lineDimensions.Any())
            {
                DBObject obj = null;
                foreach (var kvp in lineDimensions)
                {
                    if (kvp.LineObjectId == originalLine.ObjectId)
                    {
                        obj = trans.GetObject(kvp.DimensionObjectId, OpenMode.ForWrite, false);
                        if (obj != null)
                        {
                            obj.Erase();
                        }
                    }
                };
            }
        }

        // 删除原有的长度标注（假设它是DBText类型）
        private void RemoveOldLengthText(Transaction trans, BlockTableRecord btr, Line line)
        {
            foreach (ObjectId objId in btr)
            {
                DBObject obj = trans.GetObject(objId, OpenMode.ForWrite);
                if (obj is DBText dbText && IsAnnotationForLine(dbText, line))
                {
                    dbText.Erase();
                }
            }
        }

        /// <summary>
        /// 检查给定的DBText是否是针对特定线段的长度标注
        /// TODO:如果文本标注被移动了，则该方法失效
        /// </summary>
        /// <param name="dbText"></param>
        /// <param name="line"></param>
        /// <returns></returns>
        private bool IsAnnotationForLine(DBText dbText, Line line)
        {
            // 比较文本的位置和线段中点是否接近，或者其他方法来确定
            // 可以使用中点或特定的标注属性来判断
            Point3d midpoint = new Point3d(
                (line.StartPoint.X + line.EndPoint.X) / 2,
                (line.StartPoint.Y + line.EndPoint.Y) / 2,
                (line.StartPoint.Z + line.EndPoint.Z) / 2
            );

            // 计算直线的方向向量
            Vector3d direction = line.EndPoint - line.StartPoint;

            // 计算偏移量
            Vector3d offset = GetOffset(ref direction);

            // 将 offset 转化为 double 类型的长度
            double text_doffset = offset.Length;

            return dbText.Position.DistanceTo(midpoint) < text_doffset + 0.01;//这里如果有偏移量，需要加上
        }

        /// <summary>
        /// 增加长度标注-标注
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="btr"></param>
        /// <param name="lineSegment"></param>
        /// <param name="splice">是否为分割线</param>
        /// <param name="deltaLength">长度</param>
        private void AddLengthAnnotation(Transaction trans, BlockTableRecord btr, Line lineSegment, double length)
        {
            // 计算直线的中点
            Point3d midpoint = new Point3d(
                (lineSegment.StartPoint.X + lineSegment.EndPoint.X) / 2,
                (lineSegment.StartPoint.Y + lineSegment.EndPoint.Y) / 2,
                (lineSegment.StartPoint.Z + lineSegment.EndPoint.Z) / 2
            );

            // 创建 AlignedDimension 对象
            AlignedDimension dimension = new AlignedDimension(
                lineSegment.StartPoint, // 第一点
                lineSegment.EndPoint,   // 第二点
                midpoint, // 在直线上方5单位处  标注的位置 不是文字的位置
                length.ToString("F0"), // 标注文本内容，使用直线的长度
                ObjectId.Null            // 样式表
            );

            // 设置箭头样式为“无”
            dimension.Dimasz = 0;// 隐藏箭头

            // 隐藏尺寸界线
            dimension.Dimse1 = true; // 隐藏第一个尺寸界线
            dimension.Dimse2 = true; // 隐藏第二个尺寸界线

            dimension.Dimsd1 = true; // 隐藏第一个尺寸线
            dimension.Dimsd2 = true; // 隐藏第二个尺寸线

            // 设置文字样式和位置
            dimension.Dimtad = 1; // 文字在尺寸线中间
            dimension.TextPosition = midpoint + new Vector3d(offsetDistance_x, 0, 0); // 设置文本位置 TODO:需要区分x  y方向

            // 将 Dimension 对象添加到块表记录中
            var lastDimensionId = btr.AppendEntity(dimension);

            // 将待删除的标注存入字典
            int lineLength = (int)Math.Round(length, 0, MidpointRounding.AwayFromZero);
            lineDimensions.Add(new LineDimension { LineObjectId = lineSegment.ObjectId, DimensionObjectId = lastDimensionId, LineLength = lineLength });

            trans.AddNewlyCreatedDBObject(dimension, true);
        }

        private void AddLengthDBText(Transaction trans, BlockTableRecord btr, Line lineSegment, double length)
        {
            // 计算直线的中点
            Point3d midpoint = new Point3d(
                (lineSegment.StartPoint.X + lineSegment.EndPoint.X) / 2,
                (lineSegment.StartPoint.Y + lineSegment.EndPoint.Y) / 2,
                (lineSegment.StartPoint.Z + lineSegment.EndPoint.Z) / 2
            );

            // 计算直线的方向向量
            Vector3d direction = lineSegment.EndPoint - lineSegment.StartPoint;

            // 计算偏移量
            Vector3d offset = GetOffset(ref direction);

            // 计算直线与X轴的夹角，单位为弧度
            double xrota = Math.Atan2(direction.Y, direction.X);

            // 确定文本的旋转角度
            double rotation = direction.X >= 0 ? xrota : xrota + Math.PI;

            // 添加长度标注文本到块表记录中
            DBText lengthText = new DBText
            {
                Position = midpoint + offset,
                Height = 2.5,
                TextString = length.ToString("F0"), // 标注文本内容，使用直线的长度
                Rotation = rotation, // 设置文本的旋转角度
                Color = Color.FromColorIndex(ColorMethod.ByAci, 7) // 设置颜色为白色
            };

            // 将 Dimension 对象添加到块表记录中
            btr.AppendEntity(lengthText);
            trans.AddNewlyCreatedDBObject(lengthText, true);
        }

        /// <summary>
        /// 计算偏移量
        /// </summary>
        /// <param name="direction"></param>
        /// <returns></returns>
        private Vector3d GetOffset(ref Vector3d direction)
        {
            // 计算偏移量，使文本在直线上方或者竖线时在右方
            Vector3d offset;

            if (Math.Abs(direction.X) > Math.Abs(direction.Y)) // 直线更接近平行于X轴
            {
                offset = new Vector3d(0, offsetDistance_y, 0); // 偏移在Y方向，即上方
            }
            else // 直线更接近平行于Y轴
            {
                if (direction.Y > 0)
                {
                    offset = new Vector3d(offsetDistance_x, 0, 0); // 偏移在X方向，即右方
                }
                else
                {
                    offset = new Vector3d(-offsetDistance_x, 0, 0); // 偏移在X方向的左方
                }
            }

            return offset;
        }

        // 确定文本的旋转角度
        private static double GetRotation(double radian, int N)
        {
            double rotation = Math.Abs(radian);

            // 判断弧度范围，设置xdu变量
            int xdu;
            if (rotation >= 0 && rotation < Math.PI / 2)
            {
                if (N == 1)
                {
                    xdu = 1; // 0 - π/2 弧度 (0 - 90 度)
                }
                else
                {
                    xdu = 4;
                }
            }
            else if (Math.Abs(rotation) >= Math.PI / 2 && Math.Abs(rotation) < Math.PI)
            {
                if (N == 1)
                {
                    xdu = 2; // π/2 - π 弧度 (90 - 180 度)
                    rotation += Math.PI;
                }
                else
                {
                    xdu = 3;
                    rotation += Math.PI;
                }
            }
            else if (Math.Abs(rotation) >= Math.PI && Math.Abs(rotation) < 3 * Math.PI / 2)
            {

                if (N == 1)
                {
                    xdu = 3; // π - 3π/2 弧度 (180 - 270 度)
                    rotation += Math.PI;
                }
                else
                {
                    xdu = 2;
                    rotation += Math.PI;
                }
            }
            else
            {
                if (N == 1)
                {
                    xdu = 4; // 3π/2 - 2π 弧度 (270 - 360 度)
                }
                else
                {
                    xdu = 1;
                }
            }

            return rotation;
        }

        #endregion
    }
}
